use core::ffi::CStr;

use alloc::string::String;
use limine::{modules::InternalModule, request::ModuleRequest};
use x86_64::VirtAddr;

use crate::arch::{acpi::RSDP_REQUEST, kmm::convert_virtual_to_physical};

use super::context::THREAD_MANAGER;

const fn create_string<const N: usize>(s: &[u8; N]) -> [u8; N + 1] {
    let mut res = [0; N + 1];
    let mut i = 0;
    while i < N {
        res[i] = s[i];
        i += 1;
    }
    res[N] = 0;
    res
}

#[used]
#[unsafe(link_section = ".requests")]
static MODULE_REQUEST: ModuleRequest = ModuleRequest::new().with_internal_modules(&[
    &InternalModule::new()
        .with_path(unsafe { CStr::from_bytes_with_nul_unchecked(&create_string(b"/usr/init")) }),
    &InternalModule::new()
        .with_path(unsafe { CStr::from_bytes_with_nul_unchecked(&create_string(b"/usr/drvd")) }),
]);

pub fn init() {
    let module_response = MODULE_REQUEST.get_response().unwrap();
    let modules = module_response.modules();
    for module in modules {
        if unsafe { String::from_utf8_unchecked(module.path().to_vec()) }.contains("usr/init") {
            info!("Found usr/init module");

            let rsdp_vaddr = VirtAddr::new(RSDP_REQUEST.get_response().unwrap().address() as u64);
            let rsdp_paddr = convert_virtual_to_physical(rsdp_vaddr);

            load_module(
                module,
                Some((
                    rsdp_paddr.as_u64() as usize,
                    0xFFFFFFFFFFFFFFFF,
                    0x1,
                    0x2,
                    0x3,
                    0x4,
                )),
            );
        }
    }
}

fn load_module(
    module: &&limine::file::File,
    args: Option<(usize, usize, usize, usize, usize, usize)>,
) {
    let thread = super::context::Thread::new(
        0,
        true,
        object::File::parse(unsafe {
            core::slice::from_raw_parts(module.addr() as *const u8, module.size() as usize)
        })
        .ok(),
        args,
    );
    THREAD_MANAGER.lock().add(thread);
}

pub fn load_other_module(path: &str, args: Option<(usize, usize, usize, usize, usize, usize)>) {
    let module_response = MODULE_REQUEST.get_response().unwrap();
    let modules = module_response.modules();
    for module in modules {
        if unsafe { String::from_utf8_unchecked(module.path().to_vec()) }.contains(path) {
            info!("Found {} module", path);
            load_module(module, args);
        }
    }
}
